package com.woniuxy.user.service.impl;

import com.woniuxy.user.service.RedisService;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Service;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.JedisPoolConfig;
import redis.clients.jedis.JedisSentinelPool;
import redis.clients.jedis.exceptions.JedisConnectionException;
import redis.clients.jedis.util.Pool;

import java.util.HashSet;
import java.util.List;
import java.util.Set;

/**
 * @Author:阳佳
 * @Date: 2020/8/3 16:13
 * @Description:
 * @PACKAGE_NAME:com.woniuxy.user.service.impl
 */
@Service
@Component
public class RedisServiceImpl implements RedisService {
    private  final Logger logger = LoggerFactory.getLogger(com.woniuxy.user.service.impl.RedisServiceImpl.class);
    // redis lua scripts(supportted since redis 2.6)
    private static final String CAS_CMD = "local v=redis.call('get',KEYS[1]);local r=v;local n=#ARGV-1;local tb=ARGV[#ARGV];local succ='F';for i=1, n do if(v==ARGV[i]) then redis.call('set',KEYS[1],tb); r=tb; succ='T' break;end end;return {succ,r}";
    private static final String SUBS_CMD = "local v=redis.call('incrby',KEYS[1],0);local r=ARGV[1]-v;redis.call('set',KEYS[1],ARGV[1]);return r;";
    private volatile String CAS_KEY;
    private volatile String SUBS_KEY;
    private String redisAddr;
    private String[] addrInfo;
    private Pool<Jedis> jedisPool;
    private String sentinels;
    private long redisSubMaintainInterval = 10000;
    private int maxActive = 10;
    private int maxIdle = 5;
    private int timeOut = 2000;
    private String password;

    public void setPassword(String password) {
        this.password = password;
    }

    public void setRedisAddr(String redisAddr) {
        this.redisAddr = redisAddr;
    }

    public void setMaxActive(int maxActive) {
        this.maxActive = maxActive;
    }

    public void setMaxIdle(int maxIdle) {
        this.maxIdle = maxIdle;
    }

    public void setSentinels(String sentinels) {
        this.sentinels = sentinels;
    }

    public void init() {
        if (redisAddr == null || "".equals(redisAddr.trim()) || "NULL".equals(redisAddr.trim())) {
            logger.warn("no redis addr was configured,this redis service will be unavaliable");
            return;
        }
        JedisPoolConfig cfg = new JedisPoolConfig();
        cfg.setMaxIdle(maxIdle);// 设置最大连接数
        cfg.setMaxTotal(maxActive); //add by chenxinchao 20151016
        if (StringUtils.isNotBlank(sentinels)) {
            // addr info is a name rather than ip:port
            String[] sentinelsInfo = sentinels.split(",");
            Set<String> sentinelSet = new HashSet<>();
            for (String s : sentinelsInfo) {
                sentinelSet.add(s.trim());
            }
            if(StringUtils.isNotBlank(password)){
                jedisPool = new JedisSentinelPool(redisAddr, sentinelSet, cfg,timeOut,password);
            }else {
                jedisPool = new JedisSentinelPool(redisAddr, sentinelSet, cfg,timeOut);
            }
        } else {
            addrInfo = redisAddr.split(":");
            jedisPool = new JedisPool(cfg, addrInfo[0], Integer.valueOf(addrInfo[1]), timeOut, password);
        }
        // load cas scripts
        Jedis jedis = jedisPool.getResource();
        try {
            CAS_KEY = jedis.scriptLoad(CAS_CMD);
            SUBS_KEY = jedis.scriptLoad(SUBS_CMD);
        } finally {
            jedis.close();
        }
    }

    public void stop() {
        if (jedisPool != null) {
            jedisPool.destroy ();
        }
    }

    @Override
    public long llen(String key) {
        Jedis jedis = jedisPool.getResource();
        try {
            return jedis.llen(key);
        } catch (JedisConnectionException e) {
            jedis.close();
            throw e;
        } finally {
            if (jedis != null) {
                jedis.close();
            }
        }
    }

    @Override
    public List<String> lrange(String key, final long start, final long end) {
        Jedis jedis = jedisPool.getResource();
        try {
            return jedis.lrange(key, start, end);
        } catch (JedisConnectionException e) {
            jedis.close();
            throw e;
        } finally {
            if (jedis != null) {
                jedis.close();
            }
        }
    }


    @Override
    public boolean expire(String key, int seconds) {
        Jedis jedis = jedisPool.getResource();
        try {
            long result = jedis.expire(key, seconds);
            return result > 0;
        } catch (JedisConnectionException e) {
            jedis.close();
            throw e;
        } finally {
            if (jedis != null) {
                jedis.close();
            }
        }
    }


    @Override
    public String lTrim(String key, long start, long end) {
        Jedis jedis = jedisPool.getResource();
        try {
            return jedis.ltrim(key, start, end);
        } catch (JedisConnectionException e) {
            jedis.close();
            throw e;
        } finally {
            if (jedis != null) {
                jedis.close();
            }
        }
    }


    @Override
    public Long lpush(String key, String string) {
        Jedis jedis = jedisPool.getResource();
        try {
            return jedis.lpush(key, string);
        } catch (JedisConnectionException e) {
            jedis.close();
            throw e;
        } finally {
            if (jedis != null) {
                jedis.close();
            }
        }
    }


    @Override
    public Long lrem(String key, long count, String value) {
        Jedis jedis = jedisPool.getResource();
        try {
            return jedis.lrem(key, count, value);
        } catch (JedisConnectionException e) {
            jedis.close();
            throw e;
        } finally {
            if (jedis != null) {
                jedis.close();
            }
        }
    }



}

